package
{
	import Events.SharedData;
	import Events.UIEvent;
	
	import com.lib.playbook.dialog.DialogBase;
	import com.oosterwijk.irc.FlexIrcClient;
	import com.oosterwijk.irc.event.*;
	
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.events.ProgressEvent;
	import flash.net.SharedObject;
	import flash.net.Socket;
	import flash.text.TextFormat;
	import flash.ui.Keyboard;
	import flash.utils.ByteArray;
	
	import qnx.events.QNXApplicationEvent;
	import qnx.system.QNXApplication;
	import qnx.ui.buttons.*;
	import qnx.ui.core.*;
	import qnx.ui.data.DataProvider;
	import qnx.ui.events.ListEvent;
	import qnx.ui.events.ScrollEvent;
	import qnx.ui.listClasses.List;
	import qnx.ui.listClasses.ListSelectionMode;
	import qnx.ui.listClasses.ScrollDirection;
	import qnx.ui.text.TextInput;
	import qnx.views.NavController;
	
	import skins.Assets;
	
	import views.BaseView;
	import views.ChannelList;
	import views.ChannelView;
	import views.IRCView;
	import views.MenuBar;
	import views.PrivateChatView;
	import views.StatusView;
	
	[SWF(height="600", width="1024", frameRate="30", backgroundColor="#cccccc")]
	public class IRCClientApp extends MovieClip
	{
		//the back and next buttons //
		private var bt_snd:LabelButton;
		private var bt_conn:LabelButton;
		private var bt_sett:LabelButton;
		private var ti_input:TextInput;
		private var navController:NavController;
		private var tabArray:Array;
		private var statusTab:StatusView;
		private var channelListTab:ChannelList;
		private var tabBar:List;
		
		private var mainContainer:Container;
		private var navigationBar:Container;
		private var bodyContainer:Container;
		private var footContainer:Container;
		
		private var serverURL:String;
		private var portNumber:int;
		private var nick:String;
		private var alt:String;
		private var _menu:MenuBar;
		private var _ground:Sprite;
		public var flexIrcClient:FlexIrcClient;
		// singleton event dispatcher
		private var _singleton_event_dispatcher:SharedData = SharedData.instance;
		public function IRCClientApp()
		{
			initializeUI();
			init();
			showReleaseNotes();
		}
		protected function init():void {

			DialogBase.showOn = this.stage;
			QNXApplication.qnxApplication.addEventListener(QNXApplicationEvent.SWIPE_DOWN, showAppMenu);
			_singleton_event_dispatcher.addEventListener(MouseEvent.MOUSE_DOWN, groundClick);
			_singleton_event_dispatcher.addEventListener(UIEvent.OPEN_PRIVATE_CHAT, onOpenPrivateChat);
			_singleton_event_dispatcher.addEventListener(UIEvent.CLOSE_PRIVATE_CHAT, onClosePrivateChat);
						
			flexIrcClient = new FlexIrcClient();
			
			_menu.flexIrcClient = this.flexIrcClient;
			_menu.setCallbackFunctions();
			
			//flexIrcClient.setName(this.nick);
			setCallbackFunctions();
		}

		// UI
		private function initializeUI():void
		{
			_ground = new Sprite();
			_ground.graphics.beginFill(0x5CACEE,1.0);
			_ground.graphics.drawRect(0,0,1024,600);
			_ground.graphics.endFill();
			_ground.alpha = 0.3;
			
			// create main container //
			mainContainer = new Container();
			mainContainer.margins = Vector.<Number>([0,0,0,0]);
			mainContainer.flow = ContainerFlow.VERTICAL;
			//mainContainer.debugColor = 0xFFCC00;
			addChild(mainContainer);
			
			// create subcontainer on left side of the screen //
			navigationBar = new Container();
			navigationBar.containment = Containment.DOCK_TOP;
			navigationBar.margins = Vector.<Number>([2,2,2,2]);            
			navigationBar.size = 10;            
			//navigationBar.debugColor = 0xC0C0C0;
			navigationBar.sizeUnit = SizeUnit.PERCENT;
			navigationBar.flow = ContainerFlow.VERTICAL;
			navigationBar.align = ContainerAlign.NEAR;
			navigationBar.padding = 10;
			navigationBar.addChild(new Assets.NavigationBar());
			
			mainContainer.addChild(navigationBar);
			
			
			tabArray = [];
			statusTab = new StatusView();
			// add objects with a label property
			tabArray.push({label: "Status", view:statusTab});
			
			tabBar = new List();            
           
			tabBar.width = 1022;
			tabBar.height = 40;
			tabBar.columnWidth = 150;
			tabBar.containment = Containment.DOCK_TOP;
			tabBar.scrollDirection = ScrollDirection.HORIZONTAL;
			tabBar.setSkin(views.TabBarCellRenderer);
			
			//set the dataProvider
			tabBar.allowDeselect = false;
			tabBar.scrollBarAlpha = 0;
			tabBar.selectionMode = ListSelectionMode.SINGLE;
			tabBar.scrollDirection = ScrollDirection.HORIZONTAL;
			tabBar.dataProvider = new DataProvider(tabArray);
			tabBar.addEventListener(ListEvent.ITEM_CLICKED, onTabBarClick);
			//tabBar.addEventListener(MouseEvent.DOUBLE_CLICK, onTabBarDoubleClick);
			
			navigationBar.addChild(tabBar);
			tabBar.selectedIndex = 0;
			
			bodyContainer = new Container();
			bodyContainer.margins = Vector.<Number>([2,2,2,2]);            
			bodyContainer.size = 100;            
			//bodyContainer.debugColor = 0xFF3300;
			bodyContainer.sizeUnit = SizeUnit.PERCENT;
			bodyContainer.flow = ContainerFlow.VERTICAL;
			bodyContainer.align = ContainerAlign.NEAR;
			bodyContainer.padding = 10;
			
			navController = new NavController();
			navController.container = bodyContainer;
			navController.dataProvider = tabArray;
			navController.changeSection(statusTab);
			
			mainContainer.addChild(bodyContainer);

			// add subcontainers to main container //
			mainContainer.addChild(navigationBar);  
			mainContainer.addChild(bodyContainer);
			//mainContainer.addChild(footContainer);
			
			// call setSize //
			mainContainer.setSize(stage.stageWidth, stage.stageHeight);
			_menu = new MenuBar();

			addChild(_ground);
			addChild(_menu);
			_ground.visible = false;
		}
		private function showAppMenu(event:QNXApplicationEvent):void
		{
			if(! _menu.isVisible())
			{
				_menu.show();
				_ground.visible = true;
				_ground.addEventListener(MouseEvent.MOUSE_DOWN, groundClick);
			}
		}
		public function groundClick(event:MouseEvent):void
		{
			if(_menu.isVisible())
			{
				_menu.processEvent(event);
			} 
			
			if(!_menu.isVisible()){
				_ground.visible = false;
				_ground.removeEventListener(MouseEvent.MOUSE_DOWN, groundClick);
			}
		}
		private function onTabBarClick(event:ListEvent):void 
		{
			var item:Object = event.data;
			var view:BaseView = BaseView(item.view);
			
			notifyTabChanged();
			
			if( tabBar.selectedIndex >=0 && tabBar.selectedIndex != navController.selectedIndex )
			{
				navController.changeSection( view );
			}
		}
		
		private function onTabBarDoubleClick(event:MouseEvent):void
		{
			statusTab.appendHTML(tabBar.selectedIndex + "<br>");
		}



		private function setCallbackFunctions():void
		{
			flexIrcClient.setVerbose(true);
			flexIrcClient.addEventListener(FlexIrcClient.JOIN_EVENT,this.onJoin);
			flexIrcClient.addEventListener(FlexIrcClient.CONNECT_EVENT,this.onConnect);
			flexIrcClient.addEventListener(FlexIrcClient.NOTICE_EVENT,this.onNotice);
			flexIrcClient.addEventListener(FlexIrcClient.DISCONNECT_EVENT,this.onDisconnect);
			flexIrcClient.addEventListener(FlexIrcClient.NICK_ALREADY_IN_USE_EVENT,this.onNickNameAlreadyInUse);
			flexIrcClient.addEventListener(FlexIrcClient.IRC_CONNECTION_ERROR_EVENT,this.onConnectionError);
			flexIrcClient.addEventListener(FlexIrcClient.PRIVATE_MESSAGE_EVENT,this.onPrivateMessage);
			flexIrcClient.addEventListener(FlexIrcClient.NOTICE_EVENT,this.onNotice);
			flexIrcClient.addEventListener(FlexIrcClient.NICK_CHANGE_EVENT,this.onNickChange);
			flexIrcClient.addEventListener(FlexIrcClient.SERVER_RESPONSE_EVENT,this.onServerResponse);
			flexIrcClient.addEventListener(FlexIrcClient.CHANNEL_LIST_EVENT,this.onChannelList);
			flexIrcClient.addEventListener(FlexIrcClient.PART_EVENT, this.onPart);
			//flexIrcClient.addEventListener(FlexIrcClient.ACTION_EVENT,this.onAction);
			//var x:XMLList = this.menubarXML.children();
			
		}
		/* START OF IRC Event Handlers */
		protected function onJoin(event:ChannelEvent):void 
		{
			var channel:String = event.channel;
			var sender:String = event.sender;
			var login:String = event.login
			var hostname:String = event.hostname
			
			var myNick:String = flexIrcClient.getNick();
			if (sender == myNick)
			{
				this.addNewChannelUI(channel);
			}
			//else
			//	addLogEntry(sender + " joined channel: " + channel + ".\n");
		}
		
		protected function onConnect(event:IrcEvent):void 
		{
			//this.connected = true;
			addLogEntry("Connected.\n");
			//PopUpManager.removePopUp(connectWindow);
			//this.toggleConnectionMode(true);
		}
		
		
		protected function onDisconnect(event:IrcEvent):void 
		{
			
			//this.connected = false;
			addLogEntry("Disconnected.\n");
			//cleanupViewStack();
			//this.toggleConnectionMode(false);
			
		}
		
		
		protected function onNickNameAlreadyInUse(event:IrcEvent):void 
		{
			
			//this.connected = false;
			addLogEntry("Nickname already in use. Disconnecting. . .\n");
			//cleanupViewStack();
			//this.toggleConnectionMode(false);
			
		}
		
		protected function onConnectionError(event:ServerEvent):void 
		{
			//this.connected = false;
			addLogEntry(event.response + "\n");
			addLogEntry("Server Reports an error. Disconnecting. . .\n");
			//cleanupViewStack();
			//this.toggleConnectionMode(false);
		}
		
		protected function onServerResponse(event:IrcEvent):void 
		{
			var serverEvent:ServerEvent = event as ServerEvent;
			//addLogEntry(serverEvent.code + " " + serverEvent.response + "\n");
			addLogEntry(serverEvent.response + "\n");
		}
		
		
		protected function onPrivateMessage(event:UserEvent):void 
		{
			if(this.indexOfTab(event.sender) == -1){
				this.addNewPrivateChatUI(event.sender, event.message);
			}
		}
		protected function onAction(sender:String, login:String,hostname:String,target:String, action:String):void 
		{
			addLogEntry(sender + " says: " +action+ "\n");
		}
		
		protected function onNotice(event:UserEvent):void 
		{
			addLogEntry(event.sender + " notifies " + event.targetNick  + " of: "+event.message+ "\n");
		}
		
		protected function onNickChange(event:UserEvent):void 
		{
			//addLogEntry(event.sender + " changed his nick to " + event.newNick + "\n");
		}
		
		protected function onChannelList(event:ServerEvent):void
		{
			if(this.channelListTab == null){
				channelListTab = new ChannelList(flexIrcClient);
				channelListTab.registerListeners();
				tabBar.dataProvider.addItemAt({label:"Channel List", view:channelListTab}, 1);
			}
			channelListTab.setChannelArray(event.channelList);

			this.tabBar.scrollToIndex(1);
			this.tabBar.selectedIndex = 1;
			this.navController.changeSection(channelListTab);
			notifyTabChanged();
		
		}
		
		protected function onPart(event:ChannelEvent):void
		{
			if(event.sender == this.flexIrcClient.getNick()){
				var index:int = indexOfTab(event.channel);
				if(index != -1){
					var obj:Object =  tabBar.dataProvider.getItemAt(index);
					var ch:IRCView = obj.view as IRCView;
					ch.cleanup(this.flexIrcClient);
					tabBar.dataProvider.removeItemAt(index);
					
					this.tabBar.scrollToIndex(0);
					this.tabBar.selectedIndex = 0;
					this.navController.changeSection(statusTab);
					notifyTabChanged();
				}
			}
		}
		
		/* END OF IRC Event Handlers */
		private function onOpenPrivateChat(event:UIEvent):void
		{
			addNewPrivateChatUI(event.channel, null);
		}
		
		private function onClosePrivateChat(event:UIEvent):void
		{
			var index:int = indexOfTab(event.channel);
			if(index != -1){
				
				var obj:Object = tabBar.dataProvider.getItemAt(index);
				var ircView:IRCView = obj.view as IRCView;
				ircView.cleanup(this.flexIrcClient);

				tabBar.dataProvider.removeItemAt(index);
				
				this.tabBar.scrollToIndex(0);
				this.tabBar.selectedIndex = 0;
				this.navController.changeSection(statusTab);
				notifyTabChanged();
			}
		}
		private function notifyTabChanged():void
		{
			var evt:UIEvent = new UIEvent(UIEvent.CHANNEL_CHANGED);
			var obj:Object = tabBar.getItemAt(tabBar.selectedIndex) as Object;
			if(tabBar.selectedIndex != 0 && obj.label != "Channel List")
			{
				evt.channel = obj.label;
			}
			var channel:String = obj.label as String;
			if(channel.charAt(0) != '#'){
				evt.isPrivate = true;
			}
			_singleton_event_dispatcher.dispatchEvent(evt);
		}
		private function addNewPrivateChatUI(sender:String, firstMsg:String):void
		{
			var index:int = this.indexOfTab(sender);
			var privateChatView:PrivateChatView;
			if(index == -1)
			{
				privateChatView = new PrivateChatView(flexIrcClient, sender, firstMsg);
				privateChatView.registerListeners(this.flexIrcClient);
				tabBar.addItem({label:sender, view:privateChatView});
				index = tabBar.dataProvider.length - 1;
			} else {
				var obj:Object = tabBar.dataProvider.getItemAt(index);
				privateChatView = obj.view as PrivateChatView;
			}
			this.tabBar.scrollToIndex(index);
			this.tabBar.selectedIndex = index;
			this.navController.changeSection(privateChatView);
			notifyTabChanged();
		}
		private function addNewChannelUI(channel:String):void
		{
			var index:int = this.indexOfTab(channel);
			var channelView:ChannelView;
			if(index == -1){
				channelView = new ChannelView(this.flexIrcClient, channel);
				channelView.registerListeners(this.flexIrcClient);
				this.tabBar.dataProvider.addItem({label:channel, view:channelView});
				index = tabBar.dataProvider.length - 1;
			} else {
				var obj:Object = tabBar.dataProvider.getItemAt(index);
				channelView = obj.view as ChannelView;
			}
			
			this.tabBar.scrollToIndex(index);
			this.tabBar.selectedIndex = index;
			this.navController.changeSection(channelView);
			notifyTabChanged();
		}
		protected function addLogEntry(entry:String):void
		{
			if(entry != null && entry.length >0)
				statusTab.appendHTML(entry);
		}
		
		private function indexOfTab(channel:String):int
		{
			var i:int = 0; 
			for(;i<tabBar.dataProvider.length;i++){
				var obj:Object = tabBar.dataProvider.getItemAt(i);
				if(obj.label == channel){
					return i;
				}
			}
			//this.statusTab.appendHTML("indexOfTab(" + channel + ")=" + i + "<br>");
			return -1;
		}
		
		private function showReleaseNotes():void
		{
			var notes:String = "";
			notes += "FIRC for PlayBook v0.9<br>";
			notes += "Release notes:<br>";
			notes += "- Rewrote the UI using QNX UI components<br>";
			notes += "- Used <a href='http://code.google.com/p/flexircclient/'><u>flexircclient lib</u></a> for connection and message parsing<br>";
			notes += "- Used <a href='http://code.google.com/p/playbook-as3-lib/'><u>PlayBook community library</u></a> for dialog rendering<br>";
			notes += "<br>";
			notes += "Known issues:<br>";
			notes += "- Does not work with the irc networks that use load balancing, e.g. chat.freenode.net, but you can connect to the actual server, e.g. niven.freenode.net. This is due to the Socket bug on playbook, which is logged <a href='https://www.blackberry.com/jira/browse/TABLET-229'><u>here</u></a><br>";
			notes += "- Portrait mode will be supported in future releases<br>";
			notes += "<br>";
			notes += "Please report bugs to <a href='mailto:'><u>shuochen66@gmail.com</u></a><br>";
			notes += "-------------<br><br>";
			this.statusTab.appendHTML(notes);
		}
	}
}
